﻿/********************************************************
 * Module Name    : Application Dictionary
 * Purpose        : Controls the process              
 * Author         : Jagmohan Bhatt
 * Date           : 4 feb 2009
  ******************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VAdvantage.DataBase;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using VAdvantage.Framework;
using System.Threading;
using VAdvantage.Classes;
using System.ComponentModel;
using System.Windows.Forms;
using VAdvantage.Common;
using VAdvantage.Print;
using VAdvantage.Login;
using VAdvantage.Utility;
using VAdvantage.Logging;
using System.Windows;
using System.Windows.Threading;
using VAdvantage.WF;
using SilverlightDesktop.Controls;
using System.Windows.Controls;
using System.IO;
using VAdvantage.Process;

namespace VAdvantage.ProcessEngine
{

    /// <summary>
    /// ProcessCtl class controls the process and finally executes it
    /// </summary>
    public class ProcessCtl
    {
        private BackgroundWorker backgroundWorker1 = new BackgroundWorker();

        //private System.Windows.Forms.Timer tmrProcess = new System.Windows.Forms.Timer();

        static VLogger log = VLogger.GetVLogger(typeof(ProcessCtl).FullName);

        /**	Parenr				*/
        ASyncProcess _parent;

        public ProcessCtl(ASyncProcess parent, ProcessInfo pi, Trx trx)
        {

            //tmrProcessCtl.Tick += tmrProcessCtl_Tick;
            _parent = parent;
            _pi = pi;
            _trx = trx;
            InitializeBackgoundWorker();
        }

        bool showProgress = true;

        private ProcessInfo _pi;
        private ProcessDialog _pd;


        private void ShowModalDialog(ProcessParameter cw)
        {
            AutoResetEvent waitHandle = new AutoResetEvent(false);
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                //cw.Content = "Modal Dialog";
                cw.Closed += (s, e) => waitHandle.Set();
                cw.Show();
            });
            waitHandle.WaitOne();
        }

        static void ShowParamWindow(Object stateInfo)
        {
            ProcessParameter pp = (ProcessParameter)stateInfo;
            if (pp.InitDialog())
            {
                Deployment.Current.Dispatcher.BeginInvoke
                (delegate
                {
                    //pp.Show();
                });
            }
        }

        ProcessParameter pp = null;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="WindowNo"></param>
        /// <param name="pi"></param>
        /// <returns></returns>
        public void Process(int WindowNo)
        {
            Lock();
            MPInstance instance = null;
            try
            {
                instance = new MPInstance(Utility.Envs.GetContext(), _pi.GetAD_Process_ID(), _pi.GetRecord_ID());
            }
            catch (Exception e)
            {
                _pi.SetSummary(e.Message);
                _pi.SetError(true);
                Unlock();

                if (_parent is ASyncRefreshUI)
                {
                    ((ASyncRefreshUI)_parent).RefreshUI(null);
                }
                return;
            }

            if (!instance.Save())
            {
                _pi.SetSummary(Msg.GetMsg(Envs.GetContext(), "ProcessNoInstance", true));
                _pi.SetError(true);
                Unlock();

                if (_parent is ASyncRefreshUI)
                {
                    ((ASyncRefreshUI)_parent).RefreshUI(null);
                }
                return;
            }

            _pi.SetAD_PInstance_ID(instance.GetAD_PInstance_ID());
            Deployment.Current.Dispatcher.BeginInvoke
            (delegate
            {
                pp = new ProcessParameter(_pi, WindowNo);
                //ThreadPool.QueueUserWorkItem(new WaitCallback(ShowParamWindow), pp);
                ThreadPool.QueueUserWorkItem(delegate
                {
                    if (pp.InitDialog())
                    {
                        Deployment.Current.Dispatcher.BeginInvoke
                        (delegate
                        {
                            pp.Closed += new EventHandler(pp_Closed);
                            pp.AsyncProcessInfo = _parent;
                            pp.Show();
                        });
                    }
                    else
                    {
                        if (!backgroundWorker1.IsBusy)
                        {
                            backgroundWorker1.RunWorkerAsync();
                        }
                    }
                });
            });
        }

        void pp_Closed(object sender, EventArgs e)
        {
            if (!pp.IsOK())
            {
                _pi.SetSummary(Msg.GetMsg(Envs.GetContext(), "ProcessCancelled", true));
                _pi.SetError(true);

                if (_parent != null && _parent is VAdvantage.Apps.APanel)
                {
                    ((VAdvantage.Apps.APanel)_parent).SetBusy(false, true,null, "ProcessCancelled" );
                    Unlock();

                    if (_parent is ASyncRefreshUI)
                    {
                        ((ASyncRefreshUI)_parent).RefreshUI(null);
                    }
                }
                return;
            }

            if (!backgroundWorker1.IsBusy)
            {
                backgroundWorker1.RunWorkerAsync();
            }


        }


        /// <summary>
        /// Used in Visual editor
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="WindowNo"></param>
        /// <param name="pi"></param>
        /// <returns></returns>
        public bool Process(int windowNo, bool showParameter)
        {
            MPInstance instance = null;
            try
            {
                instance = new MPInstance(Utility.Envs.GetContext(), _pi.GetAD_Process_ID(), _pi.GetRecord_ID());
            }
            catch (Exception e)
            {
                _pi.SetSummary(e.Message);
                _pi.SetError(true);
                return false;
            }

            if (!instance.Save())
            {
                _pi.SetSummary(Msg.GetMsg(Envs.GetContext(), "ProcessNoInstance", true));
                _pi.SetError(true);
                return false;
            }

            _pi.SetAD_PInstance_ID(instance.GetAD_PInstance_ID());
            if (showParameter)
            {
                ProcessParameter pp = new ProcessParameter(_pi, windowNo);

                if (pp.InitDialog())
                {
                }
            }

            this.Run();
            return !_pi.IsError();
        }

        private bool _IsServerProcess = false;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="pi">process info object</param>
        /// <param name="pd">process dialog object</param>
        public ProcessCtl(ProcessInfo pi, VAdvantage.Framework.ProcessDialog pd)
        {
            _pi = pi;

            if (pd != null)
                _pd = pd;
        }


        volatile ReportEngine re = null;

        /// <summary>
        /// Run methods gets called through thread to fetch process information
        /// </summary>
        /// 
        //volatile ReportEngine_N re = null;

        DSProcessWorkflow.ReportInfo rep = null;

        public DSProcessWorkflow.ReportInfo Rep
        {
            get { return rep; }
            set { rep = value; }
        }

        public void Run()
        {
            bool pass = false;
            var client = AEnv.GetDSPWFClient();
            client.ExecuteProcessCompleted += (ov, ev) =>
                {
                    if (ev.Result != null )
                    {
                        if (ev.Result.ReportProcessInfo != null)
                        {
                            _pi = new ProcessInfo().FromList(ev.Result.ReportProcessInfo);
                        }
                        rep = ev.Result;
                    }
                    pass = true;

                };

            Ctx ctx = Envs.GetCtx();
            Dictionary<string, string> dic = (Dictionary<String, string>)ctx.GetMap();
            client.ExecuteProcessAsync(dic, _pi.GetAD_Process_ID(), _pi.GetTitle(), _pi.GetAD_PInstance_ID(), _pi.GetTable_ID(), _pi.GetRecord_ID());
            client.CloseAsync();

            while (!pass)
            {
                Thread.Sleep(0);
            }

            Unlock();
 

        }   //  run

        Trx _trx;
        /// <summary>
        /// Starts the process by calling the required class at run time.
        /// </summary>
        /// <returns>Returs ture or false on the sucessfull calling of the proecss</returns>
        private bool StartProcess()
        {
            log.Fine(_pi.ToString());
            try
            {
                // Assembly assembly = Assembly.LoadFrom(GlobalVariable.ASSEMBLY_NAME);
                string className = _pi.GetClassName().Replace("org.compiere.process", "VAdvantage.Process");
                className = className.Replace("org.compiere.wf", "VAdvantage.WF");
                className = className.Replace("org.compiere.report", "VAdvantage.Report");
                className = className.Replace("org.compiere.install", "VAdvantage.Install");
                className = className.Replace("org.compiere.print", "VAdvantage.Print");
                className = className.Replace("org.compiere.cmrp.process", "ViennaAdvantage.CMRP.Process");
                className = className.Replace("org.compiere.cmfg.process", "ViennaAdvantage.CMFG.Process");
                className = className.Replace("org.compiere.cwms.process", "ViennaAdvantage.CWMS.Process");
                className = className.Replace("org.compiere.cm", "VAdvantage.CM");

                

                Assembly asm = null;
                Type type = null;

                /***** Module ***********/

                try
                {
                    //string pName = className.Substring(className.LastIndexOf('.') + 1);
                    string pName = _pi.GetTitle();
                    Tuple<String,String> aInfo = null;
                    if (Envs.HasModulePrefix(pName, out aInfo))
                    {
                        asm = Assembly.Load(aInfo.Item1);
                        type = asm.GetType(className);
                    }
                }
                catch
                {

                }

                /**** END **************/

                if (type == null)
                {

                    /*Customization Process */
                    try
                    {
                        asm = Assembly.Load(GlobalVariable.PRODUCT_NAME);
                        type = asm.GetType(className);

                    }
                    catch
                    {
                        //asm = Assembly.Load(GlobalVariable.ASSEMBLY_NAME);
                    }
                }
                /*EndCustomization*/

                if (type == null)
                {
                    type = Type.GetType(className);
                }

                if (type.IsClass)
                {
                    ProcessCall oClass = (ProcessCall)Activator.CreateInstance(type);
                    if (oClass == null)
                        return false;
                    else
                        oClass.StartProcess(Utility.Envs.GetContext(), _pi, _trx);

                    if (_trx != null)
                    {
                        _trx.Commit();
                        log.Fine("Commit " + _trx.ToString());
                        _trx.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                if (_trx != null)
                {
                    _trx.Rollback();
                    log.Fine("Rollback " + _trx.ToString());
                    _trx.Close();
                }
                _pi.SetSummary("Error starting Class " + _pi.GetClassName().Replace("org.compiere", "VAdvantage"), true);
                log.Log(Level.SEVERE, _pi.GetClassName(), ex);
            }
            return !_pi.IsError();
        }


        /// <summary>
        /// Start Workflow.
        /// </summary>
        /// <param name="AD_Workflow_ID">AD_Workflow_ID </param>
        /// <returns>true if started</returns>
        private bool StartWorkflow(int AD_Workflow_ID)
        {
            //Remote process not implemented
            //Only local process is implemented
            log.Fine(AD_Workflow_ID + " - " + _pi.ToString());
            bool started = false;


            if (true) //DB.isRemoteProcess())
            {
                //Server server = CConnection.get().getServer();
                var server = AEnv.GetDSPWFClient();

                bool _running = false;
                try
                {
                    if (server != null)
                        //{	//	See ServerBean
                        server.GetProcessInfoCompleted += (s, e) =>
                        {
                            if (e.serviceError == null)
                            {
                                _pi = new ProcessInfo().FromList(e.Result);
                            }
                            else
                            {

                            }

                            _running = false;

                        };
                    server.GetProcessInfoAsync(_pi.ToList(), (Dictionary<String, String>)Envs.GetCtx().GetMap(), AD_Workflow_ID);

                    // _pi = server.workflow(Env.getCtx(), _pi, AD_Workflow_ID);
                    /////log.finest("server => " + m_pi);
                    started = true;
                    _running = true;

                    while (_running)
                    {

                        System.Threading.Thread.Sleep(1);

                    }



                    //}
                }
                catch (Exception ex)
                {
                    log.Log(Level.SEVERE, "AppsServer error", ex);
                    started = false;
                }
            }




            //	Run locally
            if (!started && !_IsServerProcess)
            {
                MWorkflow wf = MWorkflow.Get(Utility.Envs.GetContext(), AD_Workflow_ID);
                MWFProcess wfProcess = null;
                if (_pi.IsBatch())
                    wfProcess = wf.Start(_pi);		//	may return null
                else
                    wfProcess = wf.StartWait(_pi);	//	may return null

                started = wfProcess != null;
            }

            return started;

        }

        /// <summary>
        /// Start the DB Process
        /// </summary>
        /// <param name="procedureName">name of the process</param>
        /// <returns></returns>
        //private bool StartDBProcess(String procedureName)
        //{
        //    if (DatabaseType.IsPostgre)  //jz Only DB2 not support stored procedure now
        //    {
        //        return false;
        //    }

        //    //  execute on this thread/connection
        //    //String sql = "{call " + procedureName + "(" + _pi.GetAD_PInstance_ID() + ")}";
        //    try
        //    {
        //        //only oracle procedure are supported
        //        OracleCommand comm = new OracleCommand();
        //        OracleConnection conn = (OracleConnection)DB.GetConnection();
        //        conn.Open();
        //        comm.Connection = conn;
        //        comm.CommandText = procedureName;
        //        comm.CommandType = CommandType.StoredProcedure;
        //        OracleCommandBuilder.DeriveParameters(comm);
        //        OracleParameter[] param = new OracleParameter[1];
        //        foreach (OracleParameter orp in comm.Parameters)
        //        {
        //            param[0] = new OracleParameter(orp.ParameterName, _pi.GetAD_PInstance_ID());
        //        }

        //        log.Fine("Executing " + procedureName + "(" + _pi.GetAD_PInstance_ID() + ")");
        //        int res = sqlexec.Oracle.OracleHelper.ExecuteNonQuery(conn, CommandType.StoredProcedure, procedureName, param);
        //        //DB.ExecuteQuery(sql, null);
        //    }
        //    catch (Exception e)
        //    {
        //        log.Log(Level.SEVERE, "Error executing procedure " + procedureName, e);
        //        _pi.SetSummary(Msg.GetMsg(Envs.GetContext(), "ProcessRunError") + " " + e.Message);
        //        _pi.SetError(true);
        //        return false;

        //    }
        //    //	log.fine(Log.l4_Data, "ProcessCtl.startProcess - done");
        //    return true;
        //}


        /// <summary>
        /// Finally unlock the process
        /// </summary>
        /// <returns></returns>
        private void Unlock()
        {
            String summary = _pi.GetSummary();
            if (summary != null && summary.IndexOf("@") != -1)
                _pi.SetSummary(Utility.Msg.ParseTranslation(Utility.Envs.GetContext(), summary));
            if (_parent != null)
            {
                if (!System.Windows.Deployment.Current.Dispatcher.CheckAccess())
                {
                    _parent.UnlockUI(_pi);
                }
                else
                {
                    Thread t = new Thread(delegate() { _parent.UnlockUI(_pi); });
                    t.CurrentCulture = Utility.Envs.GetLanguage(Utility.Envs.GetContext()).GetCulture(Utility.Envs.GetLoginLanguage(Utility.Envs.GetContext()).GetAD_Language());
                    t.CurrentUICulture = Utility.Envs.GetLanguage(Utility.Envs.GetContext()).GetCulture(Utility.Envs.GetLoginLanguage(Utility.Envs.GetContext()).GetAD_Language());
                    t.Start();
                }
            }
            //return _pi.GetSummary();
        }


        /// <summary>
        /// 
        /// </summary>
        private void Lock()
        {
            if (_parent == null)
                return;
            else
            {
              
                _parent.LockUI(_pi);
               // System.Threading.Thread.Sleep(10);// 
                //Thread t = new Thread(delegate() { _parent.LockUI(_pi); });
                //t.CurrentCulture = Utility.Envs.GetLanguage(Utility.Envs.GetContext()).GetCulture(Utility.Envs.GetLoginLanguage(Utility.Envs.GetContext()).GetAD_Language());
                //t.CurrentUICulture = Utility.Envs.GetLanguage(Utility.Envs.GetContext()).GetCulture(Utility.Envs.GetLoginLanguage(Utility.Envs.GetContext()).GetAD_Language());
               // t.Start();
            }

        }

        /// <summary>
        /// 
        /// </summary>
        private void InitializeBackgoundWorker()
        {
            backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
            backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
        }

        // This event handler is where the actual,
        // potentially time-consuming work is done.
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            this.Run();
        }

        bool checkState = false;
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            bool b = System.Windows.Deployment.Current.Dispatcher.CheckAccess();
            bool iscomplete = false;

            
            if (Rep != null)
            {
                if (Rep.Report != null)// && !IsDirectPrint)
                {
                    _pi = new ProcessInfo().FromList(Rep.ReportProcessInfo);
                    if (b)
                        new PdfViewer(rep.Report, _pi.Get_AD_PrintFormat_Table_ID(), _pi).Show();
                    else
                    {
                        System.Windows.Deployment.Current.Dispatcher.BeginInvoke(delegate
                        {
                            new PdfViewer(rep.Report, _pi.Get_AD_PrintFormat_Table_ID(), _pi).Show();
                            iscomplete = true;
                        });



                        while (!iscomplete)
                            Thread.Sleep(10);


                    }
                    //SaveDialogBox
                    //new ReportDialog(re);
                }
            }
            else
            {
                ShowMessage.Info("NoDocPrintFormat", true, "", null);
               
            }
            //tmrProcess.Stop();

            //Harwinder
            /* Refresh UI when process is Completed*/
            if (_parent is ASyncRefreshUI)
            {
                ((ASyncRefreshUI)_parent).RefreshUI(_pi);
            }
            if (_parent != null && _parent is Form)
            {
                System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                ((Form)_parent).FloatToSurface());
            }
           // obj.Hide();
           
            showProgress = false;
            //_pi = null;
            backgroundWorker1 = null;
        }
    }
}
